'''
代聪聪
第二类客户：商家
=================================================
2022.5.13
商家客户的登录、注册、修改信息
与第一类用户相比，不同点:
1、与SS连接的时候port不同：port_ss_store = 15033
2022.5.14
修改了商家的根界面为登陆界面
功能请求每一步都没有加数字签名
pk_v是什么
=================================================
'''

import tkinter as tk
import tkinter.messagebox
from tkinter import *
from tkinter import ttk
import socket
import threading

import des2
import hash
from packet import get_pack  # 用来打包
from packet import pack  # 用来解析报文
import time
import config
import mysocket


#  登陆界面
#  =========================================================
login_win = tk.Tk()  # 在主界面的上层显示
login_win.title('商家登录')
login_win.geometry('350x350+300+300')

#  登录：用户id、密码  在最外层  _lg代表登陆时的用户输入
tk.Label(login_win, text='用户ID').place(x=60, y=100)
id_lg = tk.Entry(login_win)
id_lg.place(x=130, y=100)

tk.Label(login_win, text='密  码').place(x=60, y=150)
password_lg = tk.Entry(login_win, show='*')
password_lg.place(x=130, y=150)

# 登录按钮实现，也在最外层
def log():
    id1 = id_lg.get()
    password1 = password_lg.get()
    password1_en = hash.encrypt(password1)
    # 连接AS服务器获取tgt
    s_as = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    buffer_size = 1024
    address_as = (config.addr_as, config.port_as)
    # 开始连接AS服务器
    s_as.connect(address_as)
    while True:
        ts1 = time.time()
        info2as = {"idc": id1, "passwd": password1_en, "id_tgs": 'tgs', "ts1": ts1}
        msg2as = get_pack('c_a', 'business', 'get_ticket1', content=str(info2as))  # AS认证不需要检查
        s_as.send(msg2as)
        msg2as_re = mysocket.recv(s_as)
        print('password1_en', type(password1_en), password1_en)
        content_plain = des2.decrypt(msg2as_re.content, password1_en)
        #content_plain = mysocket.recv(s_as)
        content_dic = dict(eval(content_plain))
        tgt = content_dic['tgt']
        if tgt is not None:
            tk.messagebox.showinfo(title='成功', message='请求AS认证成功')
            break
        else:
            tk.messagebox.showinfo(title='错误', message='请求AS认证失败')

    s_as.close()  # 关闭与AS连接的socket
    print('as认证结束')

        #  用tgt向TGS服务器获取st
    s_tgs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    address_tgs = (config.addr_tgs, config.port_tgs)
        #  开始连接TGS服务器
    s_tgs.connect(address_tgs)
    while True:
        kc_tgs = int(content_dic["kc_tgs"])
        ts3 = time.time()
        print("运行到了连接到TGS")
        lifetime = '480'
        authenticator = {"idc": id1, "ad_c": '', "ts_3": ts3, "Lifetime": lifetime}
        authenticator_c = des2.encrypt(str(authenticator), kc_tgs)
        info2tgs = {"idv": '', "tgt": tgt, "Authenticator_c": authenticator_c}
        msg2tgs = get_pack('c_t', 'business', 'request_ticket2', content=str(info2tgs))  # 这里C向TGS发送的消息
        mysocket.send(s_tgs, msg2tgs)
        msg2tgs_re = mysocket.recv(s_tgs)
        content2_plain = des2.decrypt(msg2tgs_re.content, kc_tgs)
        # content2_plain = mysocket.recv(s_tgs, sessionkey=kc_tgs)
        content2_dic = dict(eval(content2_plain))
        st = content2_dic["ticket"]
        # private_key_ss = str(content2_dic["private_key"])
        if st is not None:
            tk.messagebox.showinfo(title='成功', message='请求TGS票据成功')
            # print()
            break
        else:
            tk.messagebox.showinfo(title='错误', message='请求TGS票据失败')

    s_tgs.close()

    #  用ST向V请求登录
    s_ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    address_ss = (config.addr_ss, config.port_ss_store)
    s_ss.connect(address_ss)  # 连上
    print("连上V了")
    while True:
        kc_v = int(content2_dic['kc_v'])  # 强制类型转换成了int
        private_key_ss = str(content2_dic["private_key"])
        ts5 = time.time()
        _authenticator2s = {"id_c": id1, "ad_c": '', "ts_5": ts5}
        authenticator2s = des2.encrypt(str(_authenticator2s), kc_v)
        info2ss = {"ticket": st, "Authenticator_c": authenticator2s}
        msg2ss = get_pack('c_s', sign='business', control_type='message5', content=str(info2ss))
        mysocket.send(s_ss, msg2ss)  # 分片发送
        msg2ss_re = mysocket.recv(s_ss)  # 分片接收
        _content3 = des2.decrypt(msg2ss_re.content, kc_v)
        content3_dic = dict(eval(_content3))
        ts6 = content3_dic['ts6']
        pk_v = content3_dic['pk_v']
        print('pk_v: ', type(pk_v), pk_v)
        if ts6 == ts5 + 1:
            tk.messagebox.showinfo(title='成功', message='登录成功')
            # s_ss.close()
            # mysocket.send(s_ss, msg2ss)
            break
        else:
            tk.messagebox.showinfo(title='失败', message='登录失败')
            break


    login_win.withdraw()  # 隐藏登陆界面
    # 进入商家管理界面
    fun_win = tk.Toplevel(login_win)
    fun_win.title('商家管理系统')
    fun_win.geometry('800x600+200+200')
    '''fun_win.withdraw()
    fun_win.deiconify()'''

    #  功能界面功能1——修改信息
    def modify_info():
        mod_win = tk.Toplevel(fun_win)
        mod_win.title('修改商家信息界面')
        mod_win.geometry('300x300+200+200')

        #  输入框，获得修改信息
        tk.Label(mod_win, text='ID(不可更改)').place(x=20, y=20)
        tk.Label(mod_win, text=id1).place(x=100, y=20)

        tk.Label(mod_win, text='修改店名').place(x=20, y=65)
        name_md = tk.Entry(mod_win)
        name_md.place(x=100, y=65)

        tk.Label(mod_win, text='修改地址').place(x=20, y=110)
        ad_md = tk.Entry(mod_win)
        ad_md.place(x=100, y=110)

        tk.Label(mod_win, text='修改号码').place(x=20, y=155)
        tp_md = tk.Entry(mod_win)
        tp_md.place(x=100, y=155)

        def ok_mod():
            name_m = name_md.get()  # 商店名称
            ad_m = ad_md.get()  # 商店地址
            tp_m = tp_md.get()  # 商店号码

            mdinfo_req = {"id": id1, "name": name_m, "address": ad_m, "phonenumber": tp_m}
            mypacket = get_pack('c_s', 'business', 'modify_info', content=str(mdinfo_req),
                                sessionkey=kc_v, privatekey=private_key_ss)
            mysocket.send(s_ss, mypacket)
            mdinfo_re = mysocket.recv(s_ss, sessionkey=kc_v, publickey=pk_v)
            # _content4 = pack(mdinfo_re, sessionkey=kc_v, publickey=pk_v)
            if int(mdinfo_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='信息修改失败')
            else:
                tk.messagebox.showinfo(title='成功', message='信息修改成功')

                mod_win.destroy()  # 销毁修改信息页面

        # 确定按钮，触发修改功能
        tk.Button(mod_win, text='确认修改', command=ok_mod).place(x=100, y=200)

    # 功能界面功能2——余额提现
    def cash_out():
        # 余额提现界面
        out_win = tk.Toplevel(fun_win)
        out_win.title('余额提现')
        out_win.geometry('300x150+200+200')

        #  输入框
        tk.Label(out_win, text='密码').place(x=20, y=20)
        pwd_co = tk.Entry(out_win)
        pwd_co.place(x=100, y=20)

        tk.Label(out_win, text='提现金额').place(x=20, y=80)
        money_co = tk.Entry(out_win)
        money_co.place(x=100, y=80)

        def ok_cash():
            # 按钮触发发送请求功能
            pwd_o = pwd_co.get()
            money_o = money_co.get()

            out_req = {"id": id1, "passwd": pwd_o, "money": money_o}
            mypacket = get_pack('c_s', 'business', 'cash_out', content=str(out_req), sessionkey=kc_v,
                                privatekey=private_key_ss)
            mysocket.send(s_ss, mypacket)
            # out_re = mysocket.recv(s_ss)
            out_re = mysocket.recv(s_ss, sessionkey=kc_v, publickey=pk_v)
            # _content5 = pack(out_re, sessionkey=kc_v, publickey=pk_v)
            if int(out_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='余额提现失败')

            else:
                tk.messagebox.showinfo(title='成功', message='余额提现成功')

                out_win.destroy()

        tk.Button(out_win, text='确认提现', command=ok_cash).place(x=100, y=110)

    #  功能界面功能3——一键上下班
    def click_chge():

        change_req = {"id": id1}
        mypacket = get_pack('c_s', 'business', 'one_click_commuting', content=str(change_req),
                            sessionkey=kc_v, privatekey=private_key_ss)
        # send函数里面加一个flag, # ack
        mysocket.send(s_ss, mypacket, ack_flag=False)
        # flag = mysocket.send(s_ss, mypacket, ack_flag=True)
        '''if flag == -1:
            print('发送失败')
        elif flag == -2:
            print('超时')
        else:
            print('成功发送的bit数：', flag)'''

        change_re = mysocket.recv(s_ss, sessionkey=kc_v, publickey=pk_v)
        # _content6 = pack(change_re, sessionkey=kc_v, publickey=pk_v)
        if int(change_re.state) != 1:
            tk.messagebox.showinfo(title='错误', message='上班状态修改失败')
        else:
            tk.messagebox.showinfo(title='成功', message='上班状态修改成功')
            # content6_dic = dict(eval(change_re.content))
            # status = content6_dic["state"]
            tk.Label(fun_win, text=change_re.content).place(x=580, y=150)
            print(change_re.content)

    #  功能界面功能4——商品管理
    def product_mana():
        # 弹出商品管理界面
        pro_win = tk.Toplevel(fun_win)
        pro_win.title('商品管理界面')
        pro_win.geometry('800x500+200+200')

        #  输入框：商品信息
        tk.Label(pro_win, text='商品ID').place(x=420, y=20)
        pro_id = tk.Entry(pro_win)
        pro_id.place(x=500, y=20)
        id_p = pro_id.get()

        tk.Label(pro_win, text='商品名称').place(x=420, y=80)
        pro_name = tk.Entry(pro_win)
        pro_name.place(x=500, y=80)
        name_p = pro_name.get()

        tk.Label(pro_win, text='商品单价').place(x=420, y=140)
        pro_price = tk.Entry(pro_win)
        pro_price.place(x=500, y=140)
        price_p = pro_price.get()

        tk.Label(pro_win, text='商品库存').place(x=420, y=200)
        pro_stock = tk.Entry(pro_win)
        pro_stock.place(x=500, y=200)
        stock_p = pro_stock.get()



        def delete():
            #  删除商品
            dele_req = {"id": id1, "id_p": id_p}
            mypacket = get_pack('c_s', 'business', 'delete_product', content=str(dele_req),
                                sessionkey=kc_v, privatekey=private_key_ss)
            mysocket.send(s_ss, mypacket)
            dele_re = mysocket.recv(s_ss, sessionkey=kc_v, publickey=pk_v)
            # _content7 = pack(dele_re, sessionkey=kc_v, publickey=pk_v)
            if int(dele_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='删除商品失败')
            else:
                tk.messagebox.showinfo(title='成功', message='删除商品成功')

        def new():

            new_req = {"id": id1, "id_p": id_p, "name_p": name_p, "price_p": price_p, "stock_p": stock_p}
            mypacket = get_pack('c_s', 'business', 'new_product', content=str(new_req),
                                sessionkey=kc_v, privatekey=private_key_ss)
            mysocket.send(s_ss, mypacket)
            new_re = mysocket.recv(s_ss, sessionkey=kc_v, publickey=pk_v)
            # _content8 = pack(new_re, sessionkey=kc_v, publickey=pk_v)
            if int(new_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='新建商品失败')
            else:
                tk.messagebox.showinfo(title='成功', message='新建商品成功')

        def modify_product():
            # 修改商品信息
            md_req = {"id": id1, "id_o": id_p, "name_p": name_p, "price_p": price_p, "stock_p": stock_p}
            mypacket = get_pack('c_s', 'business', 'modify_product', content=str(md_req),
                                sessionkey=kc_v, privatekey=private_key_ss)
            mysocket.send(s_ss, mypacket)
            md_re = mysocket.recv(s_ss, sessionkey=kc_v, publickey=pk_v)
            # _content9 = pack(md_re, sessionkey=kc_v, publickey=pk_v)
            if int(md_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='修改商品信息失败')
            else:
                tk.messagebox.showinfo(title='成功', message='修改商品信息成功')

        def product_details():
            # 刷新商品信息
            dt_req = {}


        # 按钮布置
        tk.Button(pro_win, text='删除商品', command=delete).place(x=510, y=250)
        tk.Button(pro_win, text='新建商品', command=new).place(x=510, y=295)
        tk.Button(pro_win, text='修改商品', command=modify_product).place(x=510, y=340)
        tk.Button(pro_win, text='刷新函数', command=product_details).place(x=510, y=385)



    tk.Button(fun_win, text='修改商店信息', command=modify_info).place(x=420, y=60)
    tk.Button(fun_win, text='余额提现', command=cash_out).place(x=420, y=105)
    tk.Button(fun_win, text='一键上/下班', command=click_chge).place(x=420, y=150)
    tk.Button(fun_win, text='商品管理', command=product_mana).place(x=420, y=205)



#  注册界面
#  ==================================================
#  注册按钮，唤醒一个新的顶部界面
def reg():
    #  注册窗口
    reg_win = tk.Toplevel(login_win)
    reg_win.title('商家注册界面')
    reg_win.geometry('300x350+200+200')
    """
                商家注册
                :param id:商家id
                :param password:商家密码
                :param name: 商店名
                :param address: 商店地址
                :param phonenumber: 商店电话
                :param money: 营业额
                :return:
                """
    #  输入框 获得商家详细信息
    tk.Label(reg_win, text='商家ID').place(x=30, y=20)
    id_rg = tk.Entry(reg_win)
    id_rg.place(x=100, y=20)

    tk.Label(reg_win, text='商家密码').place(x=30, y=65)
    password_rg = tk.Entry(reg_win, show='*')
    password_rg.place(x=100, y=65)

    tk.Label(reg_win, text='商店名').place(x=30, y=110)
    name_rg = tk.Entry(reg_win)
    name_rg.place(x=100, y=110)

    '''tk.Label(reg_win, text='营业额').place(x=30, y=155)
    money_rg = tk.Entry(reg_win)
    money_rg.place(x=100, y=155)'''

    tk.Label(reg_win, text='商店地址').place(x=30, y=155)
    address_rg = tk.Entry(reg_win)
    address_rg.place(x=100, y=155)

    tk.Label(reg_win, text='商店号码').place(x=30, y=245)
    phone_rg = tk.Entry(reg_win)
    phone_rg.place(x=100, y=245)

    def ok_reg():
        # 获得用户输入 _rg代表注册时的输入信息
        id2 = id_rg.get()
        password2 = password_rg.get()
        pwd2_en = hash.encrypt(password2)
        name2 = name_rg.get()
        # money2 = money_rg.get()
        address2 = address_rg.get()
        phone2 = phone_rg.get()

        # 触发功能按钮

        # 创建socket准备连接AS
        s_as = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        buffer_size = 1024
        address_as = (config.addr_as, config.port_as)
        # 开始连接AS服务器
        s_as.connect(address_as)
        while True:
            info2as = {"id": id2, "passwd": pwd2_en}
            msg2as = get_pack('c_a', 'business', 'request_enroll', content=str(info2as))  # 请求注册的消息
            s_as.send(msg2as)
            flag_as = s_as.recv(buffer_size)
            msg2as_re = pack(flag_as)
            if int(msg2as_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='AS注册失败')

            else:
                # tk.messagebox.showinfo(title='成功', message='AS注册成功')
                print('AS注册成功')
                break
        s_as.close()  # 关闭与AS通信的socket

        #  创建socket准备连接SS
        s_ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        address_ss = (config.addr_ss, config.port_ss_store)
        s_ss.connect(address_ss)  # 连上

        while True:
            info2ss = {"id": id2, "passwd": pwd2_en, "name": name2, "address": address2,
                       "phonenumber": phone2}
            msg2ss = get_pack('c_s', 'business', 'signature', content=str(info2ss))  # 请求注册的消息
            print('注册信息', len(msg2ss), msg2ss)
            s_ss.send(msg2ss)
            flag_ss = s_ss.recv(1024)
            msg2ss_re = pack(flag_ss)
            if int(msg2ss_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='SS注册失败')
                break
            else:
                tk.messagebox.showinfo(title='成功', message='注册成功')
                # print('SS注册成功')
                break

        s_ss.close()  # 关闭与SS通信的socket

        reg_win.destroy()  # 关闭注册界面

    tk.Button(reg_win, text='确定', command=ok_reg).place(x=245, y=300)

#  修改密码界面
#  =======================================================
def alt_pwd():
    alt_win = tk.Toplevel(login_win)
    alt_win.title('修改商家信息')
    alt_win.geometry('300x300+200+200')

    #  输入框， 输入旧密码和新密码，
    tk.Label(alt_win, text='ID(不可更改)').place(x=25, y=20)
    id_alt = tk.Entry(alt_win)
    id_alt.place(x=100, y=20)

    tk.Label(alt_win, text='旧密码').place(x=25, y=65)
    password_alt = tk.Entry(alt_win)
    password_alt.place(x=100, y=65)

    tk.Label(alt_win, text='新密码').place(x=25, y=110)
    re_pwd_alt = tk.Entry(alt_win)
    re_pwd_alt.place(x=100, y=110)

    def ok_alt():
        # 获取用户输入 re_ 为修改后的信息
        id3 = id_alt.get()
        pwd3 = password_alt.get()
        pwd3_en = hash.encrypt(pwd3)  # hash加密后的密码
        re_pwd = re_pwd_alt.get()
        re_pwd_en = hash.encrypt(re_pwd)

        # 触发功能按钮

        # 创建socket准备连接AS
        s_as = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        buffer_size = 1024
        address_as = (config.addr_as, config.port_as)
        # 开始连接AS服务器
        s_as.connect(address_as)
        while True:
            info2as = {"id": id3, "passwd_old": pwd3_en, "passwd_new": re_pwd_en}
            msg2as = get_pack('c_a', 'business', 'modify_pwd', content=str(info2as))  # 请求修改的消息
            s_as.send(msg2as)
            flag_as = s_as.recv(buffer_size)
            msg_re = pack(flag_as)
            if int(msg_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='AS信息更改失败')

            else:
                # tk.messagebox.showinfo(title='成功', message='AS信息更改成功')
                print('AS信息更改成功')
                break
        s_as.close()  # 关闭与AS通信的socket

        # 创建socket准备连接SS
        s_ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        address_ss = (config.addr_ss, config.port_ss_store)
        #  开始连接SS
        s_ss.connect(address_ss)
        while True:
            info2ss = {"id": id3, "passwd_new": pwd3_en, "passwd_old": re_pwd_en}
            msg2ss = get_pack('c_s', 'business', 'modify_pwd', content=str(info2ss))  # 请求修改的消息
            s_ss.send(msg2ss)
            flag_ss = s_ss.recv(buffer_size)
            msg_re = pack(flag_ss)
            if int(msg_re.state) != 1:
                tk.messagebox.showinfo(title='错误', message='信息更改失败')
                break
            else:
                tk.messagebox.showinfo(title='成功', message='信息更改成功')
                print('SS修改信息成功')
                break

        s_ss.close()  # 关闭与SS通信的socket

        alt_win.destroy()  # 销毁修改信息窗口

    # 按钮布置，确定 唤起功能按钮
    tk.Button(alt_win, text='确定', command=ok_alt).place(x=240, y=250)


#  按钮布置：登录、注册、修改信息  在最外层
tk.Button(login_win, text='登录', command=log).place(x=80, y=200)
tk.Button(login_win, text='注册', command=reg).place(x=160, y=200)
tk.Button(login_win, text='修改密码', command=alt_pwd).place(x=240, y=200)


#  运行
if __name__ == '__main__':
    login_win.mainloop()
